--- 模块功能：mono_lcd_spi_gdew027w3命令配置
-- @author openLuat
-- @module ui.mono_lcd_spi_gdew027w3
-- @license MIT
-- @copyright openLuat
-- @release 2020.08.27
require "common"
module(..., package.seeall)
-- GDEW027W3(-T) 墨水屏的分辨率
local Max_Column = 264
local Max_Row = 176
-- 墨水屏状态检测脚
local getBusy = pins.setup(13, nil, pio.PULLUP)
-- 墨水屏是否忙
function chkstatus()
    repeat
        Write_Command(0x71)
        sys.wait(200)
    log.info("----> lcd busy:", getBusy() ~= 1)
    until getBusy() == 1
end
-- 墨水屏写命令
function Write_Command(cmd)
    disp.write(0x00020000 + cmd)
end
-- 墨水屏写数据
function Write_Data(data)
    disp.write(0x00030000 + data)
end
-- 墨水屏底层延时函数
function Write_Delay(time)
    disp.write(0x00010000 + time)
end
-- 墨水屏初始化函数
function Open()
    pm.wake("lcd")
    pmd.ldoset(15, pmd.LDO_VLCD)
    disp.init({
        width = Max_Column, --分辨率宽度，128像素；用户根据屏的参数自行修改
        height = Max_Row, --分辨率高度，64像素；用户根据屏的参数自行修改
        bpp = 16, --位深度，1表示单色。单色屏就设置为1，不可修改
        bus = disp.BUS_SPI4LINE, --led位标准SPI接口，不可修改
        yoffset = 0, --Y轴偏移
        hwfillcolor = 0x0, --填充色，黑色
        freq = 1100000, --spi时钟频率，支持110K到13M（即110000到13000000）之间的整数（包含110000和13000000）
        pinrst = pio.P0_6, --reset，复位引脚
        pinrs = pio.P0_1, --rs，命令/数据选择引脚
        initcmd = {0x00}
    })
    log.info("-------------- LCD POWER ON --------------")
    Write_Command(0x06)-- --boost soft start
    Write_Data(0x07)--A
    Write_Data(0x07)--B
    Write_Data(0x17)--C
    sys.wait(1000)
    Write_Command(0x04)
    chkstatus()
    Write_Command(0x00); --panel setting
    Write_Data(0x1B); --LUT from OTP，128x296
    Write_Command(0x16);
    Write_Data(0x00); --KW-BF   KWR-AF	BWROTP 0f
    Write_Command(0xF8); --boost设定
    Write_Data(0x60);
    Write_Data(0xa5);
    Write_Command(0xF8); --boost设定
    Write_Data(0x73);
    Write_Data(0x23);
    Write_Command(0xF8); --/boost设定
    Write_Data(0x7C);
    Write_Data(0x00);
    Write_Command(0X50);
    Write_Data(0x97); -- WBmode:VBDF 17|D7 VBDW 97 VBDB 57		WBRmode:VBDF F7 VBDW 77 VBDB 37  VBDR B7
end
-- 填充数据函数
local function Fillter()
    Write_Command(0x10)--Transfer old data
    for i = 1, 5808 do
        Write_Data(0xFF)
    end
end

-- 墨水屏刷新内存到屏幕函数
-- @param nil
-- @return nil
function Refresh()
    Write_Command(0x12)-- DISPLAY REFRESH
    sys.wait(5)-- !!!The delay here is necessary, 200uS at least!!!
    chkstatus()-- waiting for the electronic paper IC to release the idle signal
end
--- 墨水屏显示图像函数
-- @param picData：墨水屏点阵数据，一维或者二维数组
-- @return nil
function Display(picData)
    Fillter()
    Write_Command(0x13)--Transfer new data
    if type(picData) == "string" then
        for i = 1, #picData do
            Write_Data(picData:sub(i, i):byte())
        end
        return
    end
    for _, k in ipairs(picData) do
        if type(k) == "table" then
            for _, v in ipairs(k) do
                Write_Data(v)
            end
        else
            Write_Data(k)
        end
    end
    Refresh()
end
--- 墨水屏清屏函数
-- @param nil
-- @return nil
function Clean()
    Fillter()
    Write_Command(0x13)--Transfer new data
    for i = 1, 5808 do
        Write_Data(0xFF)
    end
    Refresh()
end
--- 墨水屏低功耗模式
-- @param nil
-- @return nil
function Sleep()
    -- Write_Command(0X02); --power off
    -- Write_Command(0X07); --deep sleep
    -- Write_Data(0xA5);
    disp.close()
    pm.sleep("lcd")
    pmd.ldoset(0, pmd.LDO_VLCD)
end

--- 读取BMP文件
-- @param bmp: 单色bmp图片的string 或 bmp 图片的地址字符串
-- @return table：序列化后的点阵位图数据二维数组表
function GetBmpData(bmp)
    local tmp, cnt = {}, 176
    local img = io.exists(bmp) and io.readFile(bmp):sub(0x3F, -1) or bmp:sub(0x3F, -1)
    -- BMP默认行扫描(从下往上，从左往右)
    for i = 1, 6336, 36 do
        tmp[cnt] = {}
        local str = img:sub(i, i + 32)
        for j = 1, 33 do
            tmp[cnt][j] = str:sub(j, j):byte()
        end
        cnt = cnt - 1
    end
    return tmp
end
--- 转换BMP点阵二维表数据为墨水屏可用一维数组
-- @param tab: BMP序列化后的二纬表
-- @return table: 墨水屏可用的垂直扫描一维表
function RowToColu(tab)
    local imgTab = {}
    -- 转化BMP数据为列扫描(从上到下，从左右到)
    for j = 1, 33 do
        for m = 0, 7 do
            for i = 1, 176, 8 do
                local val = 0x00
                for k = 0, 7 do
                    -- BMP 默认低位在前
                    if bit.isset(tab[i + 7 - k][j], 7 - m) then
                        val = bit.set(val, k)
                    end
                end
                imgTab[#imgTab + 1] = val
            end
        end
    end
    return imgTab
end
--- 将字符串填充到处理后的 BMP 二维表
-- @number x: 字符的起始列位置,从 0 开始,单位1表示一个字符的宽度
-- @number y: 字符的起始行位置,从 0 开始,单位1表示一个像素(0-175)
-- @string str: 要显示的字符串
-- @srtring font: 显示用的字库名称
-- @table bg: 字符串要写入的 bmp二维表
-- @boolean mode: 正常显示nil或false,其他值反显
-- @return boolean: 成功返回 true,失败返回false
function PutString(x, y, str, font, bg, mode)
    local w, h = font:lower():match(".-(%d+)x(%d+).-")
    w, h = (w - (w % 8)) / 8, tonumber(h)
    w = w == 0 and 1 or w
    y = y > Max_Row - 1 and 0 or y
    X = x > Max_Column - 1 and 0 or x
    local fontfile, error = io.open("/lua/" .. font .. ".bin", "r")
    if fontfile == nil then
        log.info("OLED_ShowChar", "fontfile-error:", error)
        return false
    end
    local exp = font:lower():find("gb2312") and 2 or 1
    for i = 1, #str, exp do
        local qh = str:sub(i, i):byte()
        if qh > 127 then
            qh = (qh - 0xA1) * 94 + (str:sub(i + 1, i + 1):byte() - 0xA1)
        end
        fontfile:seek("set", w * h * qh)
        local size = fontfile:read(w * h)
        for yi = 1, h do
            for xi = 1, w do
                local idx = w * (yi - 1) + xi
                if y + yi > Max_Row or x + xi > Max_Column / 8 then break end
                if mode then
                    bg[y + yi][x + xi] = size:sub(idx, idx):byte()
                else
                    bg[y + yi][x + xi] = 0xFF - size:sub(idx, idx):byte()
                end
            end
        end
        x = x + w
    end
    io.close(fontfile)
    return true
end
